#include <stdint.h>
#include "BaseObj.h"
#include "air780e_common.h"
#include "dataStrs.h"
#include "luat_gpio.h"
#include "luat_spi.h"

// #define LOG __platform_printf
#define LOG

luat_spi_t* _spi_cfg_cache[SPI_MAX] = {0};
// pika_dev* _spi0_dev = NULL;
// pika_dev* _spi1_dev = NULL;
static pika_dev* _spi_dev_cache[SPI_MAX] = {0};
#if 0
/**
 * luat_spi_t sfud_spi_flash = {
        .id = 0,
        .CPHA = 0,
        .CPOL = 0,
        .dataw = 8,
        .bit_dict = 0,
        .master = 1,
        .mode = 0,
        .bandrate=25600000,
        .cs = 0
    };
    
 */

typedef struct luat_spi
{
    int  id;            /**< spi id        可选  1，0*/
    int  CPHA;          /**< CPHA          可选  1，0*/  
    int  CPOL;          /**< CPOL          可选  1，0*/  
    int  dataw;         /**< 数据宽度        8：8bit */
    int  bit_dict;      /**< 高低位顺序     可选  1：MSB，   0：LSB     */  
    int  master;        /**< 设置主从模式   可选  1：主机，  0：从机     */  
    int  mode;          /**< 设置全\半双工  可选  1：全双工，0：半双工    */  
    int bandrate;       /**< 频率           最小100000， 最大25600000*/  
    int cs;             /**< cs控制引脚     SPI0的片选为GPIO8, 当配置为8时，表示启用SPI0自带片选；其他配置时，需要自行编码控制片选*/  
} luat_spi_t;
#endif
int pika_hal_platform_SPI_open(pika_dev* dev, char* name) {
    if (!((name[0] == 'S' && name[1] == 'P' && name[2] == 'I') ||
        (name[0] == 's' && name[1] == 'p' && name[2] == 'i'))) {
        return -1;
    }

    int SPI_num = atoi(name + 3);
    if (SPI_num >= SPI_MAX || SPI_num < SPI_ID0){
        return -1;
    }

    _spi_dev_cache[SPI_num] = dev; // 记录 id 和 dev的对应关系，中断服务函数要用

    if (_spi_cfg_cache[SPI_num] == NULL){
        luat_spi_t* __spi = pikaMalloc(sizeof(luat_spi_t));
        if (__spi == NULL){
            return -1;
        }
        __spi->id = SPI_num;
        dev->platform_data = __spi;
    }
    else{
        dev->platform_data = _spi_cfg_cache[SPI_num];
    }
        
    // switch (SPI_num)
    // {
    //     case SPI_ID0:
    //         _spi0_dev = dev;
    //         break;
    //     case SPI_ID1:
    //         _spi1_dev = dev;
    //         break;
    //     default:
    //         return -1;
    // }
    return 0;
}


int pika_hal_platform_SPI_ioctl_config(pika_dev* dev,
                                       pika_hal_SPI_config* cfg) {
    luat_spi_t* __spi = dev->platform_data;
    
    switch (cfg->master_or_slave) {
        case PIKA_HAL_SPI_MASTER:
            __spi->master = 1;
            break;
        case PIKA_HAL_SPI_SLAVE:
            __spi->master = 0;
            return 1;
            break;
        default:
            return -1;
    }
    switch (cfg->mode) {
        case PIKA_HAL_SPI_MODE_0:
            __spi->CPOL = 0;
            __spi->CPHA = 0;
            break;
        case PIKA_HAL_SPI_MODE_1:
            __spi->CPOL = 0;
            __spi->CPHA = 1;
            break;
        case PIKA_HAL_SPI_MODE_2:
            __spi->CPOL = 1;
            __spi->CPHA = 0;
            break;
        case PIKA_HAL_SPI_MODE_3:
            __spi->CPOL = 1;
            __spi->CPHA = 1;
            break;
        default:
            return -1;
    }
    switch (cfg->lsb_or_msb) {
        case PIKA_HAL_SPI_MSB:{
            __spi->bit_dict = 1;
            break;
        }
        case PIKA_HAL_SPI_LSB:{
            __spi->bit_dict = 0;
            break;
        }
        default:
            return -1;
    }
    switch (cfg->data_width) {
        case PIKA_HAL_SPI_DATA_WIDTH_8:{
            __spi->dataw = 8;
            break;
        }
        default:
            return -1;
    }
    __spi->mode = 0; // 先默认半双工
    __spi->bandrate = cfg->speed;
    
    if (cfg->CS != NULL){
        pika_dev* cs_dev = cfg->CS;
        __spi->cs = ((luat_gpio_cfg_t*)cs_dev->platform_data)->pin;
        pikaFree(cs_dev, sizeof(pika_dev));
    }
    else{
        __spi->cs = -1;
    }
    if (luat_spi_setup(__spi) < 0){
        __platform_printf("[ERROR] SPI_ioctl_enable failed.\r\n");
        return -1;
    }

    return 0;
}



int pika_hal_platform_SPI_read(pika_dev* dev, void* recv_buf, size_t count) {
    luat_spi_t* __spi = dev->platform_data;
    char* send_buf = pikaMalloc(count);
    pika_platform_memset(send_buf, 0xFF, count);
    size_t num = luat_spi_transfer(__spi->id, send_buf, count, recv_buf, count);
    pikaFree(send_buf, count);
    if (num != count){
        return -1;
    }
    return 0;
}

int pika_hal_platform_SPI_write(pika_dev* dev, void* send_buf, size_t count) {
    luat_spi_t* __spi = dev->platform_data;
    char* recv_buf = pikaMalloc(count);
    int num = luat_spi_transfer(__spi->id, send_buf, count, recv_buf, count);
    pikaFree(recv_buf, count);
    if (num != count){
        return -1;
    }
    return 0;
}

int pika_hal_platform_SPI_write_read(pika_dev* dev, void* send_buf, void* recv_buf,  size_t count) {
    luat_spi_t* __spi = dev->platform_data;
    size_t num = luat_spi_transfer(__spi->id, send_buf, count, recv_buf, count);
    if (num != count){
        return -1;
    }
    return 0;
}



int pika_hal_platform_SPI_ioctl_enable(pika_dev* dev) {
    luat_spi_t* __spi = dev->platform_data;
    LOG("spi id:%d, speed:%d, mode:%d, lsb_or_msb:%d\n", __spi->id, __spi->bandrate, __spi->mode, __spi->bit_dict);
    if (luat_spi_setup(__spi) < 0){
        __platform_printf("[ERROR] SPI_ioctl_enable failed.\r\n");
        return -1;
    }
    return 0;
}

int pika_hal_platform_SPI_ioctl_disable(pika_dev* dev) {
    // luat_spi_t* __spi = dev->platform_data;
    // luat_spi_close(__spi->id);
    return 0;
}

int pika_hal_platform_SPI_close(pika_dev* dev) {
    luat_spi_t* _spi_cfg = dev->platform_data;
    luat_uart_close(_spi_cfg->id);
    _spi_cfg_cache[_spi_cfg->id] = NULL;
    if (NULL != dev->platform_data) {
        pikaFree(dev->platform_data, sizeof(luat_spi_t));
        dev->platform_data = NULL;
    }
    return 0;
}


